//! 网络通信模块

use std::sync::Arc;
use reqwest::{Client, Response, StatusCode};
use serde::Serialize;
use tokio::sync::RwLock;
use tracing::{info, debug};
use url::Url;

use crate::config::ClientConfig;
use crate::error::{ClientError, ClientResult};

/// HTTP客户端
#[derive(Debug, Clone)]
pub struct HttpClient {
    client: Client,
    config: ClientConfig,
    base_url: String,
}

impl HttpClient {
    pub fn new(config: ClientConfig) -> ClientResult<Self> {
        config.validate()?;

        let client = Client::builder()
            .connect_timeout(config.connect_timeout_duration())
            .timeout(config.read_timeout_duration())
            .build()
            .map_err(|e| ClientError::NetworkError(e.to_string()))?;

        let base_url = if config.server_addr.starts_with("http") {
            config.server_addr.clone()
        } else {
            format!("http://{}", config.server_addr)
        };

        Ok(Self {
            client,
            config,
            base_url,
        })
    }

    /// 发送GET请求
    pub async fn get(&self, path: &str, params: &[(String, String)]) -> ClientResult<Response> {
        let url = format!("{}{}", self.base_url, path);
        let mut request = self.client.get(&url);

        if !params.is_empty() {
            request = request.query(params);
        }

        let response = request.send().await?;
        self.handle_response(response).await
    }

    /// 发送POST请求
    pub async fn post(&self, path: &str, data: &impl Serialize) -> ClientResult<Response> {
        let url = format!("{}{}", self.base_url, path);
        let response = self.client
            .post(&url)
            .json(data)
            .send()
            .await?;
        
        self.handle_response(response).await
    }

    /// 发送PUT请求
    pub async fn put(&self, path: &str, data: &impl Serialize) -> ClientResult<Response> {
        let url = format!("{}{}", self.base_url, path);
        let response = self.client
            .put(&url)
            .json(data)
            .send()
            .await?;
        
        self.handle_response(response).await
    }

    /// 发送DELETE请求
    pub async fn delete(&self, path: &str, params: &[(String, String)]) -> ClientResult<Response> {
        let url = format!("{}{}", self.base_url, path);
        let mut request = self.client.delete(&url);

        if !params.is_empty() {
            request = request.query(params);
        }

        let response = request.send().await?;
        self.handle_response(response).await
    }

    /// 处理响应
    async fn handle_response(&self, response: Response) -> ClientResult<Response> {
        let status = response.status();
        
        match status {
            StatusCode::OK => Ok(response),
            StatusCode::NOT_FOUND => {
                let body = response.text().await.unwrap_or_default();
                Err(ClientError::ServiceNotFound(body))
            }
            StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN => {
                let body = response.text().await.unwrap_or_default();
                Err(ClientError::AuthError(body))
            }
            status if status.is_server_error() => {
                let body = response.text().await.unwrap_or_default();
                Err(ClientError::ServerError(format!(
                    "Server returned status {}: {}", status, body
                )))
            }
            _ => {
                let body = response.text().await.unwrap_or_default();
                Err(ClientError::InvalidResponse(format!(
                    "Unexpected status {}: {}", status, body
                )))
            }
        }
    }

    /// 获取基础URL
    pub fn base_url(&self) -> &str {
        &self.base_url
    }
}

/// gRPC客户端
#[derive(Debug, Clone)]
pub struct GrpcClient {
    client: nacos_network::grpc::GrpcClient,
    config: ClientConfig,
}

impl GrpcClient {
    pub async fn new(config: ClientConfig) -> ClientResult<Self> {
        config.validate()?;

        let server_addr = if config.server_addr.starts_with("http") {
            config.server_addr.clone()
        } else {
            format!("http://{}", config.server_addr)
        };

        let client = nacos_network::grpc::GrpcClient::new(server_addr).await
            .map_err(|e| ClientError::NetworkError(e.to_string()))?;

        Ok(Self { client, config })
    }

    /// 获取gRPC客户端
    pub fn client(&self) -> &nacos_network::grpc::GrpcClient {
        &self.client
    }
}

/// 负载均衡器
#[derive(Debug, Clone)]
pub struct LoadBalancer {
    servers: Arc<RwLock<Vec<String>>>,
    current_index: Arc<RwLock<usize>>,
    strategy: LoadBalanceStrategy,
}

#[derive(Debug, Clone, Copy)]
pub enum LoadBalanceStrategy {
    RoundRobin,
    Random,
    Weighted,
}

impl LoadBalancer {
    pub fn new(servers: Vec<String>, strategy: LoadBalanceStrategy) -> Self {
        Self {
            servers: Arc::new(RwLock::new(servers)),
            current_index: Arc::new(RwLock::new(0)),
            strategy,
        }
    }

    /// 获取下一个服务器
    pub async fn next_server(&self) -> Option<String> {
        let servers = self.servers.read().await;
        if servers.is_empty() {
            return None;
        }

        match self.strategy {
            LoadBalanceStrategy::RoundRobin => {
                let mut index = self.current_index.write().await;
                let server = servers[*index].clone();
                *index = (*index + 1) % servers.len();
                Some(server)
            }
            LoadBalanceStrategy::Random => {
                use rand::Rng;
                let mut rng = rand::thread_rng();
                let index = rng.gen_range(0..servers.len());
                Some(servers[index].clone())
            }
            LoadBalanceStrategy::Weighted => {
                // 简化的权重策略，实际应该根据权重选择
                let mut index = self.current_index.write().await;
                let server = servers[*index].clone();
                *index = (*index + 1) % servers.len();
                Some(server)
            }
        }
    }

    /// 更新服务器列表
    pub async fn update_servers(&self, servers: Vec<String>) {
        let mut current_servers = self.servers.write().await;
        *current_servers = servers;
    }

    /// 获取健康的服务器
    pub async fn healthy_servers(&self) -> Vec<String> {
        // 这里应该实现健康检查
        self.servers.read().await.clone()
    }
}

/// 连接池管理
///
/// 管理HTTP和gRPC客户端连接的连接池，提供连接的复用和管理
/// 支持连接的创建、缓存、清理和故障转移
///
/// # 功能特性
/// - 连接复用：避免重复创建连接，提高性能
/// - 线程安全：支持多线程并发访问
/// - 自动清理：支持过期连接的自动清理
/// - 故障转移：自动切换到健康的服务器
#[derive(Debug)]
pub struct ConnectionPool {
    /// HTTP客户端连接池，key为服务器地址，value为对应的客户端
    http_clients: Arc<RwLock<HashMap<String, HttpClient>>>,
    /// gRPC客户端连接池，key为服务器地址，value为对应的客户端
    grpc_clients: Arc<RwLock<HashMap<String, GrpcClient>>>,
    /// 客户端配置
    config: ClientConfig,
}

use std::collections::HashMap;

impl ConnectionPool {
    pub fn new(config: ClientConfig) -> Self {
        Self {
            http_clients: Arc::new(RwLock::new(HashMap::new())),
            grpc_clients: Arc::new(RwLock::new(HashMap::new())),
            config,
        }
    }

    /// 获取HTTP客户端
    ///
    /// 从连接池中获取指定服务器地址的HTTP客户端，如果不存在则创建新连接
    ///
    /// # 参数
    /// * `server_addr` - 服务器地址，格式为 `host:port`
    ///
    /// # 返回值
    /// 返回对应的HTTP客户端
    ///
    /// # 错误处理
    /// 如果创建客户端失败，返回对应的错误信息
    pub async fn get_http_client(&self, server_addr: &str,
    ) -> ClientResult<HttpClient> {
        // 使用读写锁确保线程安全
        let mut clients = self.http_clients.write().await;
        
        // 检查缓存中是否已存在对应的客户端
        if let Some(client) = clients.get(server_addr) {
            debug!("使用缓存的HTTP客户端: {}", server_addr);
            return Ok(client.clone());
        }

        debug!("创建新的HTTP客户端: {}", server_addr);
        let mut config = self.config.clone();
        config.server_addr = server_addr.to_string();
        let client = HttpClient::new(config)?;
        
        // 将新客户端添加到缓存
        clients.insert(server_addr.to_string(), client.clone());
        info!("成功创建并缓存HTTP客户端: {}", server_addr);
        
        Ok(client)
    }

    /// 获取gRPC客户端
    pub async fn get_grpc_client(&self, server_addr: &str,
    ) -> ClientResult<GrpcClient> {
        let mut clients = self.grpc_clients.write().await;
        
        if let Some(client) = clients.get(server_addr) {
            return Ok(client.clone());
        }

        let mut config = self.config.clone();
        config.server_addr = server_addr.to_string();
        let client = GrpcClient::new(config).await?;
        
        clients.insert(server_addr.to_string(), client.clone());
        Ok(client)
    }

    /// 移除客户端
    pub async fn remove_client(&self, server_addr: &str) {
        let mut http_clients = self.http_clients.write().await;
        let mut grpc_clients = self.grpc_clients.write().await;
        
        http_clients.remove(server_addr);
        grpc_clients.remove(server_addr);
    }

    /// 清理所有客户端
    pub async fn clear(&self) {
        let mut http_clients = self.http_clients.write().await;
        let mut grpc_clients = self.grpc_clients.write().await;
        
        http_clients.clear();
        grpc_clients.clear();
    }
}

/// 健康检查器
#[derive(Debug, Clone)]
pub struct HealthChecker {
    client: HttpClient,
}

impl HealthChecker {
    pub fn new(config: ClientConfig) -> ClientResult<Self> {
        let client = HttpClient::new(config)?;
        Ok(Self { client })
    }

    /// 检查服务器健康状态
    pub async fn check_health(&self, server_addr: &str,
    ) -> ClientResult<bool> {
        let mut url = Url::parse(&format!("http://{}", server_addr))
            .map_err(|e| ClientError::ConfigError(e.to_string()))?;
        
        url.set_path("/health");
        
        match self.client.client.get(url).send().await {
            Ok(response) => Ok(response.status().is_success()),
            Err(_) => Ok(false),
        }
    }

    /// 批量检查服务器健康状态
    pub async fn check_servers(&self, servers: &[String],
    ) -> ClientResult<Vec<(String, bool)>> {
        let mut results = Vec::new();
        
        for server in servers {
            let health = self.check_health(server).await?;
            results.push((server.clone(), health));
        }
        
        Ok(results)
    }
}

pub type ServerHealth = String;

#[cfg(test)]
mod tests {
    use super::*;
    use wiremock::{MockServer, Mock, ResponseTemplate};
    use wiremock::matchers::{method, path};

    #[tokio::test]
    async fn test_http_client_creation() {
        let config = ClientConfig::default();
        let client = HttpClient::new(config).unwrap();
        
        assert!(client.base_url().contains("127.0.0.1"));
    }

    #[tokio::test]
    async fn test_http_client_request() {
        let mock_server = MockServer::start().await;
        
        Mock::given(method("GET"))
            .and(path("/test"))
            .respond_with(ResponseTemplate::new(200).set_body_json(json!({"status": "ok"})))
            .mount(&mock_server)
            .await;

        let mut config = ClientConfig::default();
        config.server_addr = mock_server.address().to_string();
        
        let client = HttpClient::new(config).unwrap();
        let response = client.get("/test", &[]).await.unwrap();
        
        assert_eq!(response.status(), 200);
    }

    #[tokio::test]
    async fn test_load_balancer_round_robin() {
        let servers = vec![
            "127.0.0.1:8848".to_string(),
            "127.0.0.1:8849".to_string(),
            "127.0.0.1:8850".to_string(),
        ];
        
        let lb = LoadBalancer::new(servers, LoadBalanceStrategy::RoundRobin);
        
        assert_eq!(lb.next_server().await.unwrap(), "127.0.0.1:8848");
        assert_eq!(lb.next_server().await.unwrap(), "127.0.0.1:8849");
        assert_eq!(lb.next_server().await.unwrap(), "127.0.0.1:8850");
        assert_eq!(lb.next_server().await.unwrap(), "127.0.0.1:8848");
    }

    #[tokio::test]
    async fn test_connection_pool() {
        let config = ClientConfig::default();
        let pool = ConnectionPool::new(config);
        
        let client = pool.get_http_client("127.0.0.1:8848").await.unwrap();
        assert_eq!(client.base_url(), "http://127.0.0.1:8848");
        
        // 测试缓存
        let client2 = pool.get_http_client("127.0.0.1:8848").await.unwrap();
        assert_eq!(client.base_url(), client2.base_url());
    }

    #[tokio::test]
    async fn test_health_checker() {
        let mock_server = MockServer::start().await;
        
        Mock::given(method("GET"))
            .and(path("/health"))
            .respond_with(ResponseTemplate::new(200))
            .mount(&mock_server)
            .await;

        let config = ClientConfig::default();
        let checker = HealthChecker::new(config).unwrap();
        
        let health = checker.check_health(&mock_server.address().to_string()).await.unwrap();
        assert!(health);
    }

    #[tokio::test]
    async fn test_error_handling() {
        let mock_server = MockServer::start().await;
        
        Mock::given(method("GET"))
            .and(path("/notfound"))
            .respond_with(ResponseTemplate::new(404))
            .mount(&mock_server)
            .await;

        let mut config = ClientConfig::default();
        config.server_addr = mock_server.address().to_string();
        
        let client = HttpClient::new(config).unwrap();
        let result = client.get("/notfound", &[]).await;
        
        assert!(matches!(result, Err(ClientError::ServiceNotFound(_))));
    }

    #[tokio::test]
    async fn test_grpc_client_creation() {
        // 由于需要实际的服务器，这里只测试配置验证
        let config = ClientConfig::default();
        let result = GrpcClient::new(config).await;
        
        // 应该返回网络错误，因为没有实际的服务器
        assert!(result.is_err());
    }

    #[tokio::test]
    async fn test_url_parsing() {
        let config = ClientConfig {
            server_addr: "example.com:8848".to_string(),
            ..Default::default()
        };
        
        let client = HttpClient::new(config).unwrap();
        assert_eq!(client.base_url(), "http://example.com:8848");
    }

    #[tokio::test]
    async fn test_tls_url() {
        let config = ClientConfig {
            server_addr: "https://example.com:8848".to_string(),
            ..Default::default()
        };
        
        let client = HttpClient::new(config).unwrap();
        assert_eq!(client.base_url(), "https://example.com:8848");
    }

    use serde_json::json;
}